import jQuery from 'jquery';

const _functionMap = new WeakMap();
const _listenerMap = new WeakMap();

class NativeEventBridge {
    constructor(bridge) {
        this._bridgeInterface = bridge;
        for(const key in defaultBridge) {
            if(this._bridgeInterface[key] === undefined) {
                this._bridgeInterface[key] = defaultBridge[key];
            }
        }
        _functionMap.set(this, {});
        _listenerMap.set(this, {});
    }

    get FunctionMap() {
        return _functionMap.get(this);
    }

    get ListenerMap() {
        return _listenerMap.get(this);
    }

    callNative() {
        if (arguments.length < 2) {
            return;
        }
        const className = arguments[0], methodName = arguments[1], argLen = arguments.length - 2;
        if (argLen === 0) {
            return this._bridgeInterface.invokeMethod(className, methodName);
        } else if (argLen === 1) {
            this._bridgeInterface.printLog('==IcPlayer Player callNative: ' + className + "." + methodName + " arg=" + JSON.stringify(arguments[2]));
            let result = this._bridgeInterface.invokeMethod(className, methodName, JSON.stringify(arguments[2]));
            try {
                return JSON.parse(result);
            } catch (e) {
                return {};
            }
        }
    }

    callNativeAsync() {
        if (arguments.length < 3) {
            return;
        }
        const className = arguments[0], methodName = arguments[1];
        let fn = arguments[2], callback;
        if (typeof fn === 'function') {
            callback = this._addCallbackFunc(fn);
            return this._bridgeInterface.invokeMethodAsync(className, methodName, callback);
        } else {
            const param = fn;
            fn = arguments[3];
            if (typeof fn === 'function') {
                callback = this._addCallbackFunc(fn);
                return this._bridgeInterface.invokeMethodAsync(className, methodName, callback, JSON.stringify(param));
            }
        }
    }

    registerListener(name, fn, scope) {
        const key = this._addListenerFunc(name, fn, scope);
        const callBack = "Bridge.listenerInvokeFromNative('" + key + "',==param==)";
        this._bridgeInterface.registerListener(name, callBack);
    }

    listenerInvokeFromNative(callId, param) {
        const listener = this.ListenerMap[callId];
        if (listener === undefined || listener.callback === undefined) {
            return;
        }
        listener.callback.call(listener.scope, param);
    }

    callBackFromNative(callId, param) {
        const func = this.FunctionMap[callId];
        if (func === undefined) {
            this.FunctionMap[callId] = undefined;
            return;
        }
        func(param);
        this.FunctionMap[callId] = null;
    }

    unRegisterListener(name, key) {
        const callBack = "Bridge.listenerInvokeFromNative('" + key + "',==param==)";
        this._removeListenerFunc(key);
        this._bridgeInterface.unRegisterListener(name, callBack);
    }

    _addListenerFunc(event, fn, scope) {
        const key = this.randomKey(10);
        this.ListenerMap[key] = {
            eventName: event,
            callback: fn,
            scope: scope || window
        };
        return key;
    }

    _removeListenerFunc(key) {
        delete this.ListenerMap[key];
    }

    _addCallbackFunc(fn) {
        const key = this.randomKey(10);
        this.FunctionMap[key] = fn;
        return "Bridge.callBackFromNative('" + key + "',==param==)";
    }

    randomKey(len) {
        const x = "0123456789qwertyuioplkjhgfdsazxcvbnm", timestamp = new Date().getTime();
        let tmp = "";
        for (let i = 0; i < len; i++) {
            tmp += x.charAt(Math.ceil(Math.random() * 100000000) % x.length);
        }
        return timestamp + tmp;
    }
}

const defaultBridge = {
    'invokeMethod': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
        return {};
    },
    'printLog': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    },
    'invokeMethodAsync': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    },
    'registerListener': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    },
    'unRegisterListener': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    },
    'prepareSwitchPage': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    },
    'onPageLoaded': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    },
    'onMainLoaded': function () {
        console.warn('this message from default bridge! there is noting happening here!!');
    }
};

export {NativeEventBridge};